package com.marinesky.common.shiro;

import com.alibaba.fastjson.JSON;
import com.marinesky.common.shiro.utils.ShiroByteSource;
import com.marinesky.model.business.ShiroUser;
import com.marinesky.model.constants.Status;
import com.marinesky.model.entity.Role;
import com.marinesky.model.entity.User;
import com.marinesky.service.base.IResourceService;
import com.marinesky.service.base.IRoleService;
import com.marinesky.service.base.IUserService;
import org.apache.log4j.Logger;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.*;

/*
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         佛祖保佑       永无BUG
//          佛曰:
//                  写字楼里写字间，写字间里程序员；
//                  程序人员写程序，又拿程序换酒钱。
//                  酒醒只在网上坐，酒醉还来网下眠；
//                  酒醉酒醒日复日，网上网下年复年。
//                  但愿老死电脑间，不愿鞠躬老板前；
//                  奔驰宝马贵者趣，公交自行程序员。
//                  别人笑我忒疯癫，我笑自己命太贱；
//                  不见满街漂亮妹，哪个归得程序员？
/
                     Created by Marinesky on 2017/4/26.
 */
public class ShiroDbRealm extends AuthorizingRealm {

    private final Logger log = Logger.getLogger(getClass());

    @Resource
    private IUserService userService;

    @Resource
    private IRoleService roleService;

    @Resource
    private IResourceService resourceService;

    public ShiroDbRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
        super(cacheManager, matcher);
    }

    /**
     * 判断进行授权
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();

        Set<String> roleIds = new HashSet<String>();
        for (int i=0;i<shiroUser.getRoles().size();i++){
            roleIds.add(shiroUser.getRoles().get(i).getId().toString());
        }
        Set<String>  resourceIds = new HashSet<String>();
        for (int i=0;i<shiroUser.getResources().size();i++){
            resourceIds.add(shiroUser.getResources().get(i).getId().toString());
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();


        info.setRoles(roleIds);
        info.addStringPermissions(resourceIds);
        return info;
    }

    /**
     * 判断进行认证(比如说登录,原理：用户提交 用户名和密码  --- shiro 封装令牌 ---- realm 通过用户名将密码查询返回 ---- shiro 自动去比较查询出密码和用户输入密码是否一致---- 进行登陆控制)
     * 封装登录认证的角色和资源信息(roles,urls)
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        log.debug("doGetAuthenticationInfo[token:"+ JSON.toJSONString(token)+"]");
        UsernamePasswordToken loginToken = (UsernamePasswordToken) token;

        Map<String,Object> params = new HashMap<>();
        params.put("login_name",loginToken.getUsername());
        params.put("status", Status.ENABLE.getStatus());
        User user =userService.get(params);
        //账户不存在或已失效
        if(user==null){
            return null;
        }
        ShiroUser shiroUser = new ShiroUser(user);
        //获取登录用户所属角色

        params.clear();
        params.put("userId",user.getId());
        params.put("status",Status.ENABLE.getStatus());
        List<Role> roles = roleService.find(params);
        List<com.marinesky.model.entity.Resource> resources = new ArrayList<>();
        if(roles!=null && !roles.isEmpty()){
            List<BigInteger> roleIds = new ArrayList<>();
            for(int i=0;i<roles.size();i++){
                roleIds.add(roles.get(i).getId());
            }
            params.clear();
            params.put("status",Status.ENABLE.getStatus());
            params.put("roleIds",roleIds);
            resources = resourceService.find(params);

        }
        shiroUser.setRoles(roles);
        shiroUser.setResources(resources);


        // 认证缓存信息
        return new SimpleAuthenticationInfo(shiroUser, user.getPassword().toCharArray(),
                ShiroByteSource.of(user.getSalt()), getName());
    }
}
